﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data.SqlClient;
using System.Data.Sql;
using System.Data;
using System.IO;
using System.Windows.Forms;
using System.Collections;
using System.Data.Objects;
using System.Data.Objects.DataClasses;

namespace Inference
{
    public class LV
    {
        SqlCommand InsertCommand, DeleteCommand, SelectCommand, UpdateCommand, SelectForSlot;
        SqlDataAdapter adapter;
        SqlConnection Connection;
        int FirstFrame, GoalFrame;
        public bool Abort;
        List<int> IDExamples = new List<int>(); // список фреймов-прототипов, у которых есть экземпляры
        List<int> IDActFrames = new List<int>(); // список фреймов-прототипов из акта привязки
        List<int> BadEntities = new List<int>(); // cписок не привязавшихся сущностей
        List<int> CheckedFrames = new List<int>(); // список уже просмотренных фреймов в акте привязки
        List<int> IncompleteFrames = new List<int>(); // список частично определенных фреймов
        TaleEntities TaleContext = new TaleEntities();
        int NextDomain = 0;


        public LV(string ConnectionString)
        {
            Connection = new SqlConnection(ConnectionString);
            Connection.Open();
            InsertCommand = new SqlCommand("", Connection);
            DeleteCommand = new SqlCommand("", Connection);
            SelectCommand = new SqlCommand("", Connection);
            UpdateCommand = new SqlCommand("", Connection); 
            SqlConnection connec = new SqlConnection(ConnectionString); connec.Open();
            SelectForSlot = new SqlCommand("", connec);
            adapter = new SqlDataAdapter("", Connection);
            // инициализация
            SelectCommand.CommandText = "Select * from SysTable";
            SqlDataReader rd = SelectCommand.ExecuteReader(); rd.Read();
            FirstFrame = Convert.ToInt32(rd[0]);
            GoalFrame = Convert.ToInt32(rd[1]);
            rd.Close();
            Abort = false;            
            // инициализация ActiveRecord
            //ActiveRecordStarter.Initialize(ActiveRecordSectionHandler.Instance, typeof(Log));
            //ActiveRecordStarter.CreateSchema();

            //var props = new Dictionary<string, string>() {
            //{ "connection.driver_class", typeof(NHibernate.Driver.OleDbDriver).AssemblyQualifiedName },
            //{ "dialect", typeof(NHibernate.Dialect.MsSql2005Dialect).AssemblyQualifiedName },
            //{ "connection.provider", typeof(NHibernate.Connection.DriverConnectionProvider).AssemblyQualifiedName },
            //{ "connection.connection_string", "Data Source="+"Provider=SQLOLEDB;"+ Directory.GetCurrentDirectory() + "\\Tale.mdf" },
            //{ "proxyfactory.factory_class", typeof(NHibernate.ByteCode.Castle.ProxyFactoryFactory).AssemblyQualifiedName },
            //{ "show_sql", "true"}
            //};

            //var source = new InPlaceConfigurationSource();
            //source.Add(typeof(ActiveRecordBase), props);
            //ActiveRecordStarter.Initialize(Assembly.GetExecutingAssembly(), source);
            //ActiveRecordStarter.UpdateSchema();

            //InPlaceConfigurationSource source = new InPlaceConfigurationSource();
            //source.Add(typeof(ActiveRecordBase), props);
            //ActiveRecordStarter.Initialize(source, typeof(Log));

            //        IConfigurationSource config = ; 

            //ActiveRecordStarter.Initialize(config, typeof(Log));
            //ActiveRecordStarter.Initialize(new XmlConfigurationSource("appconfig.xml"), typeof(Log));
            //ActiveRecordStarter.CreateSchema();

            //TaleContext = new TaleEntities();
            //TaleContext.

        }

        public Slot GetSlotByID(int SlotID)
        {
            IEnumerable<KeyValuePair<string, object>> entityKeyValues =
                     new KeyValuePair<string, object>[] { new KeyValuePair<string, object>("ID", SlotID) };
            Slot sl = (Slot)TaleContext.GetObjectByKey(new EntityKey("TaleEntities.Slot", entityKeyValues));
            return sl;
        }

        public void FixValueSlot(int SlotID, int ValueID, bool success)
        {
            TaleEntities qwe = new TaleEntities();
            // означивание слота
            //if (success)
            //{
            IEnumerable<KeyValuePair<string, object>> entityKeyValues =
                  new KeyValuePair<string, object>[] { new KeyValuePair<string, object>("ID", SlotID) };
            Slot sl = (Slot)qwe.GetObjectByKey(new EntityKey("TaleEntities.Slot", entityKeyValues));
            SelectCommand.CommandText = "Select ValueID from SlotValues where SlotID=" + SlotID.ToString();
            if (SelectCommand.ExecuteScalar() == null)
            {
                SlotValues val = new SlotValues();
                val.ValueID = ValueID;
                val.Slot = sl;
                qwe.AddToSlotValues(val);
            }
            else
            {
                //UpdateCommand.CommandText = "Update SlotValues set ValueID=" + ValueID.ToString() + " where SlotID=" + SlotID.ToString();
                //UpdateCommand.ExecuteNonQuery();
                int qq = TaleContext.SlotValues.Where(v => v.SlotID == SlotID).First().ValueID;
                qwe.SlotValues.Where(v => v.SlotID == SlotID).First().ValueID = ValueID;
            }
            //}
            // добавление записи в лог            
            InsertCommand.Parameters.Clear();
            InsertCommand.CommandText = "Insert into Log values(@slot,@reason,@value)";
            InsertCommand.Parameters.AddWithValue("value", ValueID);
            InsertCommand.Parameters.AddWithValue("slot", SlotID);
            InsertCommand.Parameters.AddWithValue("reason", success);
            InsertCommand.ExecuteNonQuery();
            InsertCommand.Connection.Close();
            InsertCommand.Connection.Open();
            //Log lo = new Log();
            //lo.ValueID = ValueID;
            //lo.Success = success;
            //lo.SlotID = SlotID;
            //lo.Slot = sl;
            //qwe.AddToLog(lo);


            qwe.SaveChanges();
            TaleContext.Refresh(RefreshMode.StoreWins, TaleContext.SlotValues);
        }

        public  string GetRoot(int FrameID)
        {
            Frame fr;
            do
            {
                fr = TaleContext.Frame.Where(f => f.ID == FrameID).First();
                if (fr.Is_a.HasValue)
                    FrameID = fr.Is_a.Value;
                else
                    FrameID = 0;
            }
            while (FrameID != 0);
            return fr.Name;
        }

        List<int> GetParents(int SlotID) // получить родительские слоты данного слота
        {
            List<int> parents = new List<int>();
            ViewSlotFrame vsf = TaleContext.ViewSlotFrame.Where(v => v.ID == SlotID).First();

            do
            {
                if (vsf.Is_a.HasValue)
                {
                    if (TaleContext.ViewSlotFrame.Where(v => (v.FrameID == vsf.Is_a.Value && v.Name == vsf.Name)).Count() > 0)
                    {
                        vsf = TaleContext.ViewSlotFrame.Where(v => (v.FrameID == vsf.Is_a.Value && v.Name == vsf.Name)).First();
                        parents.Add(vsf.ID);
                    }
                    else
                        break;
                }
            }
            while (vsf.Is_a.HasValue);
            parents.Reverse();
            return parents;
        }


        public bool CheckMarker(int FrameID, int SlotID, int IdValue, int mode)
        {
            bool test = true;
            var marks = from s in TaleContext.Fact where s.Slot.ID == SlotID select s;

            foreach (var mark in marks)
            {
                SelectCommand.CommandText = "Select ID from ProductionFact where FactID=" + mark.ID.ToString();
                if (SelectCommand.ExecuteScalar() == null) // если маркер
                {
                    int CompID = mark.CompSlotID; string name = GetSlotByID(CompID).Name;
                    if (mode == 1) // проверка родительских маркеров
                        CompID = TaleContext.ViewSlotFrame.Where(c => (c.Name == name && c.FrameID == FrameID)).First().ID;
                    SelectCommand.CommandText = "Select ValueID from SlotValues where SlotID=" + CompID;
                    int val = Convert.ToInt32(SelectCommand.ExecuteScalar());
                    if (val == 0) // если проверяет себя
                        val = IdValue;

                    if ((val == mark.ValueID) == mark.Negation)
                        test = false;
                }
            }
            return test;
        }

        public bool CheckMarkerForSub(int FrameID, int SlotID, int mode)
        {
            bool test = true;
            var marks = from s in TaleContext.Fact where s.Slot.ID == SlotID select s;
            
            foreach (var mark in marks)
            {
                SelectCommand.CommandText = "Select ID from ProductionFact where FactID=" + mark.ID.ToString();
                if (SelectCommand.ExecuteScalar() == null) // если маркер
                {
                    string name = GetSlotByID(mark.CompSlotID).Name;
                    int val = 0;
                    int CompID = TaleContext.ViewSlotFrame.Where(c => (c.Name == name && c.FrameID == FrameID)).First().ID;
                    if (mode == 0)
                        //SelectCommand.CommandText = "Select ValueID from SlotValues where SlotID=" + CompID;
                        //val = Convert.ToInt32(SelectCommand.ExecuteScalar());
                        val = TaleContext.SlotValues.Where(s => s.SlotID == CompID).First().ValueID;
                    else
                        val = TaleContext.Slot.Where(s => s.ID == CompID).First().DefaultValue.Value; 
                    if ((val == mark.ValueID) == mark.Negation)
                        test = false;
                }
            }
            return test;
        }

        public bool CheckSlotValue(int SlotID, int IdValue)
        {
            bool test = true;
            Slot sl = GetSlotByID(SlotID);

            // проверка родительских маркеров
            List<int> parents = GetParents(SlotID);
            foreach (int id in parents)
            {
                if (test)
                    test = CheckMarker(sl.Frame.ID, id, IdValue, 1);
            }

            // проверка своего маркера
            if (test)
                test = CheckMarker(0, SlotID, IdValue, 2);

            // проверка по наследованию
            if (sl.Domains.ID != 1 && sl.Inheritance == 2) // if !subframe & same
                if (sl.DefaultValue.Value != IdValue)
                    test = false;
            return test;
        }

        public bool CheckSlotSub(int SlotID, int IdFrame, int mode)
        {
            bool test = true;
            Slot sl = GetSlotByID(SlotID);

            // проверка родительских маркеров
            List<int> parents = GetParents(SlotID);
            foreach (int id in parents)
            {
                if (test)
                    test = CheckMarkerForSub(IdFrame, id, mode);
            }

            // проверка своего маркера
            if (test)
                test = CheckMarkerForSub(IdFrame, SlotID, mode);

            return test;
        }

        public bool CheckSlotValue1(int SlotID, int IdValue)
        {
            bool test = true;
            Slot sl = GetSlotByID(SlotID);

            // проверка родительских маркеров
            List<int> parents = GetParents(SlotID);
            foreach (int id in parents)
            {
                if (test)
                    test = CheckMarker(sl.Frame.ID, id, IdValue, 1);
            }

            // проверка своего маркера
            if (test)
                test = CheckMarker(0, SlotID, IdValue, 2);

            //// проверка по наследованию
            //if (sl.Domains.ID != 1 && sl.Inheritance == 2) // if subframe & same
            //    if (sl.DefaultValue.Value != IdValue)
            //        test = false;
            return test;
        }

        public int CheckProductions(int SlotID)
        {
            DataTable TableRules = new DataTable();
            int IDValue = 0; bool test = true;
            List<int> IdSlots = new List<int>();

            Slot sl = GetSlotByID(SlotID);

            if (!(GetRoot(sl.Frame.ID) == "ситуация" && sl.Name.ToLower() == "next")) // если не для поля Next
            {
                IdSlots = GetParents(SlotID);
            }
            IdSlots.Add(SlotID);

            var prods = from s in TaleContext.ViewProductions select s;

            foreach (var rule in prods)
            {
                if (IdSlots.Contains(rule.SlotID))
                {
                    int FactValueID = rule.ValueID;
                    int CompTarget = rule.CompSlotID;
                    if (rule.ID != SlotID) // если проверяем родительские слоты
                    {
                        //if (GetSlotByID(rule.Place.Value).Domains.ID==1) // если субфрейм
                        //{
                        //    SelectCommand.CommandText = "Select Inheritance from ViewSlotFrame where Name='" 
                        //        + GetSlotByID(rule.Place.Value).Name + "' and FrameID=" + GetSlotByID(rule.SlotID).Frame.ID;
                        //    if (SelectCommand.ExecuteScalar().ToString() == "1") // если override
                        //        continue;
                        //}

                        SelectCommand.CommandText = "Select ID from ViewSlotFrame where Name='" + GetSlotByID(CompTarget).Name
                            + "' and FrameID=" + sl.Frame.ID.ToString();
                        int target = Convert.ToInt32(SelectCommand.ExecuteScalar());
                        if (target != 0) // если субфрейм
                            CompTarget = target;
                    }

                    if (test && rule.Type == 1) // проверка факта в посылке
                    {
                        //SelectCommand.c
                        SelectCommand.CommandText = "Select ValueID from SlotValues where SlotID=" + CompTarget.ToString();
                        int val = Convert.ToInt32(SelectCommand.ExecuteScalar());
                        if ((val == FactValueID) == Convert.ToBoolean(rule.Negation))
                            test = false;
                    }
                    if (test && rule.Type == 2 && (CheckSlotValue(CompTarget, FactValueID))) //  означивание слота
                    {
                        FixValueSlot(CompTarget, FactValueID, true);
                        //return FactValueID;
                        IDValue = FactValueID;
                    }
                    if (rule.Type == 3) // обязательное заключение
                    {
                        FixValueSlot(CompTarget, FactValueID, true);
                    }
                    if (rule.Type == 2)
                        test = true;
                }

            }
            return IDValue;
        }


        int FindChildExample(int SlotID, int FrameID)
        {
            List<int> ChildExams = ChildrenOf(FrameID);
            ChildExams.Add(FrameID);
            ChildExams = ChildExams.Intersect(IDExamples).ToList();
            int TargetFrame = -1;
            if (FrameID == 15)
            {
            };
            List<int> GoodFrames = new List<int>();
            foreach (int ChildID in ChildExams)
                if (CheckSlotSub(SlotID, ChildID, 0))
                {
                    //TargetFrame = ChildID;
                    //break;
                    GoodFrames.Add(ChildID);
                }
            if (GoodFrames.Count>0)
                TargetFrame=GoodFrames[new Random().Next(0,GoodFrames.Count-1)];
            return TargetFrame;
        }

        int RunConsult(Slot sl)
        {
            Dictionary<int, string> vv = new Dictionary<int, string>();
            Consult cons = new Consult();
            List<int> IllegalValues = new List<int>();

            SelectCommand.CommandText = "Select Name from Frame where ID=" + sl.Frame.ID.ToString();
            cons.Text = SelectCommand.ExecuteScalar().ToString() + "/" + sl.Name;

            var values = from s in TaleContext.ViewDomains where s.DomID == sl.Domains.ID orderby s.Number select s;
            foreach (var val in values) // составление словаря значений домена
            {
                vv.Add(val.ID, val.Value);
                if (!CheckSlotValue(sl.ID, val.ID))
                    IllegalValues.Add(val.ID);
            }

            if (sl.DefaultValue.HasValue)
                cons.SetQuestion(sl.Question, vv, sl.DefaultValue.Value, IllegalValues);
            else
                cons.SetQuestion(sl.Question, vv, 0, IllegalValues);
            cons.ShowDialog();
            if (!cons.success) // отменили консультацию
            {
                Abort = true;
                return -1;
            }
            else
                if (cons.IdAnswer != -1)
                    return cons.IdAnswer;
                else
                    if (TaleContext.Slot.Where(s => s.ID == sl.ID).First().AllowNull) // проверка задания отсутствия
                    {
                        if (TaleContext.Slot.Where(s => s.ID == sl.ID).First().DefaultValue.HasValue)
                            return TaleContext.Slot.Where(s => s.ID == sl.ID).First().DefaultValue.Value;
                        else
                            return -1; // !!!
                    }
                    else
                        return -1;
        }


        void CreateExample(int FrameID)
        {
            var Slots = from s in TaleContext.Slot where s.Frame.ID == FrameID select s;

            foreach (Slot sl in Slots)
            {
                if (sl.Number != 0) // not Name
                {
                    //if (sl.Domain != 1)
                    if (!sl.DomainType.HasValue || sl.DomainType.Value==0)
                        FixValueSlot(sl.ID, sl.DefaultValue.Value, true);
                    else
                    {
                        CreateExample(TaleContext.ViewFrameExample.Where(f => f.SlotID == sl.ID).First().ID);
                        FixValueSlot(sl.ID, sl.DefaultValue.Value, true);
                    }
                }
                else
                    FixValueSlot(sl.ID, sl.DefaultValue.Value, true);
            }
            IDExamples.Add(FrameID);
            IncompleteFrames.Remove(FrameID);
        }

        public bool BindingSlot(int SlotID)
        {
            int IdValue = 0, idval = 0; bool Result = true;
            if (Abort)
                return false;
            var Slots = from s in TaleContext.Slot where s.ID == SlotID select s;
            Slot sl = Slots.FirstOrDefault();

            //if (sl.Domains.ID != 1) // если  слот не субфрейм
            if (!sl.DomainType.HasValue || sl.DomainType.Value==0)
            {
                idval = CheckProductions(SlotID);
                //if (IdValue==0) // если продукции не сработали/их нет
                if (TaleContext.SlotValues.Where(v => v.Slot.ID == SlotID).Count() == 0) // слот не означен
                {
                    int ResCons = RunConsult(sl);
                    if (ResCons != -1)
                        IdValue = ResCons;
                    else
                        IdValue = sl.DefaultValue.Value;
                }
                else
                    IdValue = TaleContext.SlotValues.Where(v => v.Slot.ID == SlotID).First().ValueID; // берем старое значение                
            }
            else // если субфрейм
            {
                // !!!!!
                int FrameId = TaleContext.ViewFrameExample.Where(f => f.SlotID == SlotID).First().ID; //по заданию отсутствия

                if (sl.DomainType > 0)
                {
                    if (sl.Inheritance == 1)
                    {
                        int ChildExample = FindChildExample(SlotID, sl.DomainType.Value);
                        if (ChildExample == -1) // нет подходящих экземпляров потомков и фрейма-домена
                        {
                            if (!IDExamples.Contains(FrameId) && CheckSlotSub(SlotID, FrameId, 1)) // проверка задания отсутствия
                            {
                                //IdValue = FrameId;
                                IdValue = TaleContext.ViewFrameExample.Where(f => f.ID == FrameId).First().ValueID;
                                CreateExample(FrameId);
                            }
                            else
                            {
                                //int ResCons = RunConsult(sl); // косяк
                                //if (ResCons != -1)
                                //    IdValue = ResCons;
                                if ((!IDExamples.Contains(FrameId) &&
                                    BindingFrame(FrameId)) && CheckSlotSub(SlotID, FrameId, 0))
                                    IdValue = sl.DefaultValue.Value;
                                else // консультация неуспешна
                                {
                                    if (sl.DomainType != FrameId) // есть ли иерархия
                                    {
                                        int ParentID = -1;
                                        if (TaleContext.Frame.Where(f => f.ID == FrameId).First().Is_a.HasValue)
                                            ParentID = TaleContext.Frame.Where(f => f.ID == FrameId).First().Is_a.Value;
                                        while ((IdValue == 0 && ParentID != -1) && ParentID != sl.DomainType) // по иерархии
                                        {
                                            if (CheckSlotSub(SlotID, ParentID, 1))
                                            {
                                                //IdValue = ParentID; // косяк
                                                IdValue = TaleContext.ViewFrameExample.Where(f => f.ID == ParentID).First().ValueID;
                                                CreateExample(ParentID);
                                            }
                                            else
                                                if (TaleContext.Frame.Where(f => f.ID == ParentID).First().Is_a.HasValue)
                                                    ParentID = TaleContext.Frame.Where(f => f.ID == ParentID).First().Is_a.Value;
                                                else
                                                    ParentID = -1;
                                        }
                                        if (IdValue == 0)
                                        {
                                            FixValueSlot(SlotID, sl.DefaultValue.Value, false);
                                            return false;
                                        }

                                    }
                                    FixValueSlot(SlotID, sl.DefaultValue.Value, false);
                                    return false;
                                }
                            }
                        }
                        else
                            IdValue = TaleContext.ViewFrameExample.Where(f => f.ID == ChildExample).First().ValueID;
                    }
                    else // inheritance=same
                    {
                        if (!IDExamples.Contains(FrameId))
                        {
                            if (CheckSlotSub(SlotID, FrameId, 1)) // проверка задания отсутствия
                            {
                                //IdValue = FrameId;
                                IdValue = TaleContext.ViewFrameExample.Where(f => f.ID == FrameId).First().ValueID;
                                CreateExample(FrameId);
                            }
                            else
                            {
                                //int ResCons = RunConsult(sl);
                                //if (ResCons != -1)
                                //    IdValue = ResCons;
                                //else
                                //    return false;
                                if (BindingFrame(FrameId) && CheckSlotSub(SlotID, FrameId, 0))
                                    IdValue = sl.DefaultValue.Value;
                                else
                                {
                                    FixValueSlot(SlotID, sl.DefaultValue.Value, false);
                                    return false;
                                }
                            }
                        }
                        else
                            IdValue = TaleContext.ViewFrameExample.Where(f => f.SlotID == SlotID).First().ValueID;
                    }
                }
                else // domaintype=0
                {
                    IdValue = TaleContext.ViewFrameExample.Where(f => f.SlotID == SlotID).First().ValueID;
                    if (BadEntities.Contains(FrameId)) // данный фрейм-прототип уже не смог прив-ся
                        //return false;
                        Result = false;
                    if (!IDExamples.Contains(FrameId)) // у данного фрейма-прототипа нет экземпляра
                        if (!BindingFrame(FrameId))
                            Result = false;
                    //  return false;
                }
            }

            // bool res = CheckSlotValue(SlotID, IdValue);
            if (Result)
                Result = CheckSlotValue(SlotID, IdValue);
            if (idval != IdValue)
                FixValueSlot(SlotID, IdValue, Result); // фиксация значения слота и его лога

            return Result;
        }


        int Levels(int FrameID) // глубина дерева
        {
            int count = 0, max = 0;
            var frames = from f in TaleContext.Frame where f.Is_a == FrameID select f;

            if (frames.Count() > 0)
                count = 1;
            foreach (var frame in frames)
            {
                int l = Levels(frame.ID);
                if (l > max)
                    max = l;
            }

            return (count + max);
        }

        int NextFrame(int FrameID)
        {
            int IdNextFrame = 0;
            List<int> IdLeaves = new List<int>();
            List<int> IdTrees = new List<int>();
            var frames = from f in TaleContext.Frame where f.Is_a == FrameID select f;

            foreach (var frame in frames) // формирование списков листьев и деревьев
                if (TaleContext.Frame.Where(f => f.Is_a == frame.ID).Count() == 0) // нет потомков
                    IdLeaves.Add(frame.ID);
                else
                    IdTrees.Add(frame.ID);

            foreach (int leave in IdLeaves) // проверка листьев
                if (!IDExamples.Contains(leave) && !IDActFrames.Contains(leave))
                    return leave;

            IdTrees = IdTrees.OrderBy(tr => Levels(tr)).ToList();
            foreach (int tree in IdTrees) // проверка поддеревьев
                if (!CheckedFrames.Contains(tree))
                {
                    int res = NextFrame(tree);
                    if (res != 0)
                        return res;
                }


            if (!IDExamples.Contains(FrameID) && !IDActFrames.Contains(FrameID))
                return FrameID;

            // переход вверх по иерархии
            if (TaleContext.Frame.Where(f => f.ID == FrameID).First().Is_a.HasValue)
            {
                int yy = TaleContext.Frame.Where(f => f.ID == FrameID).First().Is_a.Value;
                CheckedFrames.Add(FrameID);
                int ee = NextFrame(yy);
                if (ee != 0)
                    return ee;
            }

            return IdNextFrame;
        }


        public List<int> ChildrenOf(int FrameID)
        {
            List<int> res = new List<int>();
            var children = from fCurrent in TaleContext.Frame
                           join fAnother in TaleContext.Frame on fCurrent.ID equals fAnother.Is_a
                           where fCurrent.ID == FrameID
                           select fAnother;
            foreach (Frame f in children)
            {
                res.Add(f.ID);
                res.AddRange(ChildrenOf(f.ID));
            }
            return res;
        }

        void GoAway(int FrameID)
        {
            IDActFrames.Add(FrameID);
            // добавление потомков в стоп-лист
            if (!IDExamples.Contains(FrameID))
                IDActFrames.AddRange(ChildrenOf(FrameID).ToArray());
            CheckedFrames.Clear();
            int NF = 0;
            if (TaleContext.Frame.Where(f => f.ID == FrameID).First().Is_a.HasValue)
                NF = NextFrame(TaleContext.Frame.Where(f => f.ID == FrameID).First().Is_a.Value);
            else
                NF = NextFrame(FrameID);
            if (NF != 0)
                BindingFrame(NF);
        }


        bool BindingFrame(int FrameID)
        {
            if (NextDomain != 0)
                if ((FrameID != NextDomain && !ChildrenOf(NextDomain).Contains(FrameID)) && (GetRoot(FrameID).ToLower() == "ситуация"))
                    Abort = true;
            if (Abort)
                return false;
            int IdNext = 0, NextValue = 0;
            List<int> IDSlots = new List<int>();
            var Slots = from s in TaleContext.Slot orderby s.Number where s.Frame.ID == FrameID select s;

            foreach (var sl in Slots)
            {
                IDSlots.Add(sl.ID);
                if (sl.Number != 0) // имя фрейма
                {
                    if ((GetRoot(FrameID).ToLower() == "ситуация") && sl.Number == Slots.Count() - 1) // next
                    {
                        IdNext = sl.ID;
                        if (sl.DefaultValue.HasValue)
                            NextValue = sl.DefaultValue.Value;
                    }
                    else // если не next
                    {
                        if (!BindingSlot(sl.ID)) // фрейм не привязался
                        {
                            // чистка значений слотов экземпляра
                            //foreach (int id in IDSlots)
                            //{
                            //    DeleteCommand.CommandText = "Delete from SlotValues where SlotID=" + id.ToString();
                            //    DeleteCommand.ExecuteNonQuery();
                            //}

                            if (GetRoot(FrameID).ToLower() == "ситуация")
                            {
                                if (!IncompleteFrames.Contains(FrameID))
                                    IncompleteFrames.Add(FrameID);
                                GoAway(FrameID); // идем куда-то ...
                            }
                            else
                                BadEntities.Add(FrameID);

                            return false;
                        }
                    }
                }
                else
                    FixValueSlot(sl.ID, sl.DefaultValue.Value, true);
            }
            // фрейм привязался
            IDExamples.Add(FrameID);
            IncompleteFrames.Remove(FrameID);
            if (GetRoot(FrameID).ToLower() == "ситуация")
                IDActFrames.Clear();
            if (FrameID == GoalFrame || ChildrenOf(GoalFrame).Contains(FrameID))
            {
                CheckProductions(IdNext);
                //MessageBox.Show("Означили целевой фрейм");

            }
            else
                if (GetRoot(FrameID).ToLower() == "ситуация") // если это фрейм-ситуация
                {
                    int n = CheckProductions(IdNext);
                    if (n != 0)
                        NextValue = TaleContext.ViewFrameExample.Where(f => f.ValueID == n).First().ID;
                    if (NextValue != 0) // если слот next определен
                    {       
                        if (!IDExamples.Contains(NextValue))
                        {
                            NextDomain = TaleContext.Slot.Where(s => s.ID == IdNext).First().DomainType.Value;
                            BindingFrame(TaleContext.ViewFrameExample.Where(f => f.ID == NextValue).First().ID);
                        }
                        else
                            GoAway(FrameID);
                    }
                    else
                    {
                        GoAway(FrameID);
                    }
                }

            return true;
        }

        void ClearMemory()
        {
            foreach (int FrameID in IncompleteFrames)
            {
                var Slots = from s in TaleContext.SlotValues where s.Slot.Frame.ID == FrameID select s;
                foreach (var sl in Slots)
                    TaleContext.DeleteObject(sl);
            }
            TaleContext.SaveChanges();
        }

        public void StartConclusion()
        {
            // чистка лога
            DeleteCommand.CommandText = "Delete from Log";
            DeleteCommand.ExecuteNonQuery();
            //удаление фреймов-экземпляров
            DeleteCommand.CommandText = "Delete from SlotValues";
            DeleteCommand.ExecuteNonQuery();

            Dictionary<int, string> vv = new Dictionary<int, string>();
            Consult cons = new Consult();
            List<int> IllegalValues = new List<int>();

            cons.Text = "Выбор начала сказки";

            //var values = from s in TaleContext.ViewDomains where s.Name.ToLower() == "имена фреймов-ситуаций" orderby s.Number select s;
            List<int> values = ChildrenOf(25); values.Add(25);

            //foreach (var val in values) // составление словаря значений домена
            //{
            //    vv.Add(val.ID, val.Value);
            //}

            foreach (int val in values) // составление словаря значений домена
            {
                vv.Add(val,TaleContext.Frame.Where(f=>f.ID==val).First().Name);
            }

            cons.SetQuestion("С чего начинается сказка?", vv, 0, IllegalValues);
            cons.ShowDialog();
            if (cons.success) // отменили консультацию
            {
                if (cons.IdAnswer != -1)
                {
                    //string FirstValue = TaleContext.DValues.Where(v => v.ID == cons.IdAnswer).First().Value.ToLower().Trim();
                    //FirstFrame = TaleContext.Frame.Where(f => f.Name.ToLower().Trim() == FirstValue).First().ID;                    
                    FirstFrame = cons.IdAnswer;
                }
                else
                {                    
                    //List<DomainsValues> rr = TaleContext.DomainsValues.Where(d => d.DomID == 7).ToList();
//                    int r = rr[new Random().Next(0,rr.Count-1)].Value;
                    List<int> aa = ChildrenOf(25);
                    aa.Add(25);
                    int r = aa[new Random().Next(0, aa.Count - 1)];
                    //string FirstValue = TaleContext.DValues.Where(v => v.ID ==r ).First().Value.ToLower().Trim();
                    //FirstFrame = TaleContext.Frame.Where(f => f.Name.ToLower().Trim() == FirstValue).First().ID;
                    FirstFrame = r;
                }
                Consult cons2 = new Consult();
                cons2.SetQuestion("Чем заканчивается сказка?", vv, 0, IllegalValues);
                cons2.ShowDialog();

                if (cons2.success)
                {
                    if (cons2.IdAnswer != -1)
                    {
                        //string GoalValue = TaleContext.DValues.Where(v => v.ID == cons2.IdAnswer).First().Value.ToLower().Trim();
                        //GoalFrame = TaleContext.Frame.Where(f => f.Name.ToLower().Trim() == GoalValue).First().ID;
                        GoalFrame = cons2.IdAnswer;
                    }
                    else
                    {
                        //List<DomainsValues> rr = TaleContext.DomainsValues.Where(d => d.DomID == 7).ToList();
                        List<int> aa = ChildrenOf(25); aa.Add(25);
                        //int r = rr[ new Random().Next(0, rr.Count - 1)].Value;
                        int r = aa[new Random().Next(0, aa.Count - 1)];
                        //string GoalValue = TaleContext.DValues.Where(v => v.ID == r).First().Value.ToLower().Trim();
                        //GoalFrame = TaleContext.Frame.Where(f => f.Name.ToLower().Trim() == GoalValue).First().ID;
                        GoalFrame = r;
                    }
                    UpdateCommand.CommandText = "Update systable set first=" + FirstFrame.ToString() +
                        ",goal=" + GoalFrame.ToString();
                    UpdateCommand.ExecuteNonQuery();

                    //SysTable sys = new SysTable();
                    //sys.First=FirstFrame;
                    //sys.Goal=GoalFrame;
                    //TaleContext.AddToSysTable(sys);
                    //TaleContext.SaveChanges();

                    BindingFrame(FirstFrame);
                    ClearMemory();
                    MessageBox.Show("Консультация закончена");
                    ReasonForm rf = new ReasonForm(TaleContext);
                    rf.ShowDialog();
                }
            }
            Connection.Close();
        }


    }
}
